/**
 * Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.stylefeng.guns.core.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.guns.core.common.constant.dictmap.base.AbstractDictMap;
import cn.stylefeng.guns.core.common.constant.dictmap.factory.DgFieldDoFactory;
import cn.stylefeng.guns.core.common.constant.dictmap.factory.DictFieldWarpperFactory;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

/**
 * 对比两个对象的变化的工具类
 *
 * @author fengshuonan
 * @Date 2017/3/31 10:36
 */
public class Contrast {

    //记录每个修改字段的分隔符
    public static final String separator = ";;;";

    /**
     * 比较两个对象,并返回不一致的信息
     *
     * @author stylefeng
     * @Date 2017/5/9 19:34
     */
    public static String contrastObj(Object pojo1, Object pojo2) {
        String str = "";
        try {
            Class clazz = pojo1.getClass();
            Field[] fields = pojo1.getClass().getDeclaredFields();
            int i = 1;
            for (Field field : fields) {
                if ("serialVersionUID".equals(field.getName())) {
                    continue;
                }
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                Method getMethod = pd.getReadMethod();
                Object o1 = getMethod.invoke(pojo1);
                Object o2 = getMethod.invoke(pojo2);
                if (o1 == null || o2 == null) {
                    continue;
                }
                if (o1 instanceof Date) {
                    o1 = DateUtil.formatDate((Date) o1);
                }
                if (!o1.toString().equals(o2.toString())) {
                    if (i != 1) {
                        str += separator;
                    }
                    str += "字段名称" + field.getName() + ",旧值:" + o1 + ",新值:" + o2;
                    i++;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 比较两个对象pojo1和pojo2,并输出不一致信息
     *
     * @author stylefeng
     * @Date 2017/5/9 19:34
     */
    //重要改变：key的形式,，如account{account,name,birthday,sex,email,phone,jobnum,position,grade,entrytime,dimissiontime}
    //{ }前的字段要为索引即确定唯一性，如果一个不行就多个如：account,name,birthday
    //{ }中的字段即为改变时要记录的字段，英文逗号隔开
    public static String contrastObj(Class dictClass, String key, Object pojo1, Map<String, String> pojo2) throws IllegalAccessException, InstantiationException {
        AbstractDictMap dictMap = (AbstractDictMap) dictClass.newInstance();
        //去掉key中的空格
        String key0 = key.replaceAll(" ","");
        int index1 = key0.indexOf("{");
        int index2 = key0.indexOf("}");
        //先把{ }中的字段以字符串取出，再转化为String数组
        String feildsStr = key0.substring(index1+1,index2);
        String[] feildsArr =feildsStr.split(",");
        //取出索引字段，如account，或者account,name,birthday
        String keyOne = key0.substring(0,index1);
        //用guns写的 parseMutiKey方法包装keyOne的字段
        String str = parseMutiKey(dictMap, keyOne, pojo2) + separator;
        try {
            Class clazz = pojo1.getClass();
            //拿到对应实体类中的字段
            Field[] fields = pojo1.getClass().getDeclaredFields();
            int i = 1;
            for (Field field : fields) {
                //主要改动
                //因为修改的字段是一部分字段，许多前端没有的字段都在对应实体类中有，会出很多问题
                //所以就指定要记录修改的字段即{ }中的，此处就是判断 拿到的字段在不在指定的字段中
                for(int n = 0; n < feildsArr.length; n++){
                    if( feildsArr[n].equals(field.getName())){
                        if ("serialVersionUID".equals(field.getName())) {
                            continue;
                        }
                        PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                        Method getMethod = pd.getReadMethod();
                        Object o1 = getMethod.invoke(pojo1);
                        Object o2 = pojo2.get(StrUtil.lowerFirst(getMethod.getName().substring(3)));
                        if ((o1 == null || "".equals(o1)) && (o2 == null || "".equals(o2))) {
                            continue;
                        }
                        if (o1 instanceof Date) {
                            o1 = DateUtil.formatDate((Date) o1);
                        } else if (o1 instanceof Integer) {
                            o1 = o1.toString();
                            //o2 = Integer.parseInt(o2.toString());
                        }

                        //对象为null时tostring就会报错，处理为空串，不为null时转字符串
                        String stro1 = "";
                        if(o1 != null){
                            stro1 = o1.toString();
                        }
                        String stro2 = "";
                        if(o2 != null){
                            stro2 = o2.toString();
                        }
                        //o1和o2两个字符串不相等时记录日志
                        if (!o1.equals(o2)) {
                            if (i != 1) {
                                str += separator;
                            }
                            //拿到字段名称
                            String fieldName = dictMap.get(field.getName());
                            //如果fieldWarpperMethod有拿到名称
                            String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(field.getName());
                            //如果fieldDgDictory有拿到名称（dxl加的）
                            String fieldDgDictoryName = dictMap.getFieldDgDictoryName(key);

                            //有fieldDgDictory时，先执行
                            if(fieldDgDictoryName != null){
                                //用DgFieldDoFactory.createMapWarpper拿到对应字段包装的值
                                String o1Warpper = DgFieldDoFactory.createMapWarpper(stro1, fieldDgDictoryName);
                                String o2Warpper = DgFieldDoFactory.createMapWarpper(stro2, fieldDgDictoryName);
                                str += "字段名称：" + fieldName + "；旧值：" + o1Warpper + "，新值：" + o2Warpper +"。";
                            }else if (fieldWarpperMethodName != null) {
                                //用DictFieldWarpperFactory.createFieldWarpper拿到对应字段包装的值
                                Object o1Warpper = DictFieldWarpperFactory.createFieldWarpper(o1, fieldWarpperMethodName);
                                Object o2Warpper = DictFieldWarpperFactory.createFieldWarpper(o2, fieldWarpperMethodName);
                                //包装日志消息，转成字符串
                                str += "字段名称：" + fieldName + "；旧值：" + o1Warpper + "，新值：" + o2Warpper +"。";
                            } else {
                                str += "字段名称：" + fieldName + "；旧值：" + o1 + "，新值：" + o2 +"。";
                            }
                            i++;
                        }
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return str;
    }

    /**
     * 比较两个对象pojo1和pojo2,并输出不一致信息
     *
     * @author stylefeng
     * @Date 2017/5/9 19:34
     */
    public static String contrastObjByName(Class dictClass, String key, Object pojo1, Map<String, String> pojo2) throws IllegalAccessException, InstantiationException {
        AbstractDictMap dictMap = (AbstractDictMap) dictClass.newInstance();
        String str = parseMutiKey(dictMap, key, pojo2) + separator;
        try {
            Class clazz = pojo1.getClass();
            Field[] fields = pojo1.getClass().getDeclaredFields();
            int i = 1;
            for (Field field : fields) {
                if ("serialVersionUID".equals(field.getName())) {
                    continue;
                }
                String prefix = "get";
                int prefixLength = 3;
                if (field.getType().getName().equals("java.lang.Boolean")) {
                    prefix = "is";
                    prefixLength = 2;
                }
                Method getMethod = null;
                try {
                    getMethod = clazz.getDeclaredMethod(prefix + StrUtil.upperFirst(field.getName()));
                } catch (java.lang.NoSuchMethodException e) {
                    System.err.println("this className:" + clazz.getName() + " is not methodName: " + e.getMessage());
                    continue;
                }
                Object o1 = getMethod.invoke(pojo1);
                Object o2 = pojo2.get(StrUtil.lowerFirst(getMethod.getName().substring(prefixLength)));
                if (o1 == null || o2 == null) {
                    continue;
                }
                if (o1 instanceof Date) {
                    o1 = DateUtil.formatDate((Date) o1);
                } else if (o1 instanceof Integer) {
                    o2 = Integer.parseInt(o2.toString());
                }
                if (!o1.toString().equals(o2.toString())) {
                    if (i != 1) {
                        str += separator;
                    }
                    String fieldName = dictMap.get(field.getName());
                    String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(field.getName());
                    if (fieldWarpperMethodName != null) {
                        Object o1Warpper = DictFieldWarpperFactory.createFieldWarpper(o1, fieldWarpperMethodName);
                        Object o2Warpper = DictFieldWarpperFactory.createFieldWarpper(o2, fieldWarpperMethodName);
                        str += "字段名称:" + fieldName + ",旧值:" + o1Warpper + ",新值:" + o2Warpper;
                    } else {
                        str += "字段名称:" + fieldName + ",旧值:" + o1 + ",新值:" + o2;
                    }
                    i++;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 解析多个key(逗号隔开的)
     *
     * @author stylefeng
     * @Date 2017/5/16 22:19
     */
    public static String parseMutiKey(AbstractDictMap dictMap, String key, Map<String, String> requests) {
        StringBuilder sb = new StringBuilder();
        if (key.contains(",")) {
            String[] keys = key.split(",");
            for (String item : keys) {
                String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(item);
                String value = requests.get(item);
                if (fieldWarpperMethodName != null) {
                    Object valueWarpper = DictFieldWarpperFactory.createFieldWarpper(value, fieldWarpperMethodName);
                    sb.append(dictMap.get(item) + " = " + valueWarpper + "，" +";;;");
                } else {
                    sb.append(dictMap.get(item) + " = " + value + "，" +";;;");
                }
            }
            return StrUtil.removeSuffix(sb.toString(), ",");
        } else {
            String fieldWarpperMethodName = dictMap.getFieldWarpperMethodName(key);
            String value = requests.get(key);
            if (fieldWarpperMethodName != null) {
                Object valueWarpper = DictFieldWarpperFactory.createFieldWarpper(value, fieldWarpperMethodName);
                sb.append(dictMap.get(key) + " = " + valueWarpper +";;;");
            } else {
                sb.append(dictMap.get(key) + " = " + value +";;;");
            }
            return sb.toString();
        }
    }
    
    
    /**
      * <b>封装业务消息msg
      * </b><br><i>Description</i> :
      * @param dictMap
      * @param key
      * @param requests
      * @return String
      * <br>
      * <br><b>Throws</b> :
      * @date 2018年12月1日 下午7:17:16    <br><i>author</i> : dxl
     */
    public static String dgParseMutiKey(AbstractDictMap dictMap, String key, Map<String, String> requests) {
        StringBuilder sb = new StringBuilder();
        if (key.contains(",")) {
            //如果key中包含多个字段，把key解析成数组
            String[] keys = key.split(",");
            for (String item : keys) {

                //getFieldDgDictoryName自己写的，拿到方法名
                //有此方法，主要是因为，requests拿到的都是字符串，如sex为1或2，要1或2包装成男或女，用通用的mapper方法，
                //要传入Integer类型，但拿到的String类，写fieldDgDictory方法时候要 具体处理这个方法参数（以后顶掉guns的 DictFieldWarpperFactory）
                String fieldDgDictoryName = dictMap.getFieldDgDictoryName(item);

                //从requests拿到对应字段的值
                String value = requests.get(item);
                //应字段的值为null时，传参数时会出错，处理成空串
                if(value == null){
                	value = "";
                }
                //用DgFieldDoFactory.createMapWarpper拿到对应字段包装的值
                if (fieldDgDictoryName != null) {
                    String parameter = DgFieldDoFactory.createMapWarpper(value, fieldDgDictoryName);
                    sb.append(dictMap.get(item) + " = " + parameter + "，*");
                    //没有fieldDgDictory方法直接使用字典包装
                } else {
                    sb.append(dictMap.get(item) + " = " + value + "，*");
                }
            }
            return StrUtil.removeSuffix(sb.toString(), ",");

            //key包含一个字段是包装
        } else {
        	String fieldDgDictoryName = dictMap.getFieldDgDictoryName(key);
            String value = requests.get(key);
            if (fieldDgDictoryName != null) {
            	String parameter = DgFieldDoFactory.createMapWarpper(value, fieldDgDictoryName);
                sb.append(dictMap.get(key) + " = " + parameter);
            } else {
                sb.append(dictMap.get(key) + " = " + value);
            }
            return sb.toString();
        }
    }
    
}